package com.study.kt._03coroutines

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext

/**
 * <pre>
 *     author : slx
 *     time   : 2021/04/04
 *     desc   :
 * </pre>
 */
/**
 * 流的收集动作总是发生在调用的协程上下文中，与定义Flow处的协程无关。这个特性为上下文保留。
 * 由于该特性flow定义出耗时，如果在主线程中使用流，就会造成流的阻塞
 */
fun main() {
    runBlocking {
        // getFlowList().collect { println(it) }
        getFlowOnList().collect { println(it) }
    }
}

// 1.改变Flow发射的上下文错误案例
private fun getFlowList(): Flow<Int> = flow {
    // 此处企图通过协程分发器改变Flow的上下文，而collect在runBlocking上下文中(此处没有指定默认在主线程)
    // Flow的生成和收集不在一个上下文就会发生异常，使用flowOn解决
    // java.lang.IllegalStateException: Flow invariant is violated:
    withContext(Dispatchers.Default) {
        for (i in 100..105) {
            delay(100)
            emit(i)
        }
    }
}

// 2.使用flowOn,使发射和收集在不同上下文，两者在不同的协程中，flowOn运算符改变了Flow本身默认的顺序性。
private fun getFlowOnList(): Flow<Int> = flow {
    for (i in 100..105) {
        delay(100)
        emit(i)
    }
}.flowOn(Dispatchers.Default)
